package com.frame.library.skin;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.text.TextUtils;

import com.frame.library.skin.attr.SkinAttr;
import com.frame.library.skin.attr.SkinView;
import com.frame.library.skin.support.SkinConfig;
import com.frame.library.skin.support.SkinPreUtils;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Added by Tom on 2024/07/02.
 * 皮肤的管理类
 */
public class SkinManager {

    private static SkinManager mInstance; // 单例：内存中反正只有一个实例。

    static { // 静态代码块，实现单例
        mInstance = new SkinManager();
    }

    public static SkinManager getInstance() {
        return mInstance;
    }

    //--------------------------------------
    private Context mContext; // 上下文
    private SkinResource mSkinResources; // 皮肤的资源管理，获取资源都是通过它获取。
    // 皮肤管理 Map，key是Activity，后面value 是Activity中的 SkinView集合。
    // Activity 要实现ISkinChangeListener接口。
    private Map<ISkinChangeListener, List<SkinView>> mSkinViews = new HashMap<>();


    private SkinManager() {
    }

    /**
     * 初始化 一般都在Application中配置, 防止内存泄漏
     *
     * @param context
     */
    public void init(Context context) {
        // 避免单例导致 内存泄漏，使用ApplicationContext
        this.mContext = context.getApplicationContext();
        // 皮肤保存路径 currentSkinPath
        String skinPath = SkinPreUtils.getInstance(mContext).getSkinPath();
//        skinPath = Environment.getExternalStorageDirectory().getAbsolutePath()
//                + File.separator + "red.skin";
        if (TextUtils.isEmpty(skinPath)) { // 防止皮肤被用户删除了。
            return;
        }
        File skinFile = new File(skinPath);
        if (!skinFile.exists()) {
            // 换肤插件的文件不存在，清空皮肤路径.
            clearSkinInfo();
            return;
        }
        // 皮肤插件的包名 packageName
        String packageName = context.getPackageManager()
                .getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES).packageName;
        if (TextUtils.isEmpty(packageName)) {
            clearSkinInfo(); // 不能获取到包名，清空皮肤路径
            return;
        }
        // TODO ,检验签名。判定是否是自己的包。mSkinResources 做初始化操作
        initSkinResource(skinPath); // 初始化皮肤资源
    }


    /**
     * 加载皮肤
     *
     * @param skinPath 目标皮肤的路径
     */
    public int loadSkin(String skinPath) {
        // TODO: 将换肤插件拷贝走，让用户不能轻易删除。比如 cache目录 下面。
        File skinFile = new File(skinPath);
        if (!skinFile.exists()) { // 1.皮肤包 文件不存在
            return SkinConfig.SKIN_FILE_NO_EXIST;
        }
        // 皮肤插件的包名
        String packageName = mContext.getPackageManager()
                .getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES)
                .packageName;
        if (TextUtils.isEmpty(packageName)) { // 判断包名称
            return SkinConfig.SKIN_FILE_ERROR; // 2.文件有错误
        }
        String currentSkinPath = SkinPreUtils.getInstance(mContext).getSkinPath();
        // 3.判断皮肤是否是一样的（已经加载过了）。避免不断地重复换肤。消耗内存资源。
        if (skinPath.equals(currentSkinPath)) {
            return SkinConfig.SKIN_LOADED; // 皮肤已经加载了，不重复加载
        }

        // 最好判断签名是否正确，后面增量更新再说
        initSkinResource(skinPath); // 初始化换肤资源
        changeSkin();   // 执行换肤
        saveSkinInfo(skinPath); // 保存皮肤的路径。用于重启app，显示最新的皮肤
        return SkinConfig.SKIN_LOAD_SUCCESS;  // 4.加载成功
    }

    /**
     * 切换皮肤
     */
    private void changeSkin() {
        // 遍历集合 mSkinViews
        for (ISkinChangeListener skinChangeListener : mSkinViews.keySet()) {
            List<SkinView> skinViews = mSkinViews.get(skinChangeListener);
            for (SkinView skinView : skinViews) {
                skinView.skin(); // 改变皮肤
            }
            // 发送通知，通知Activity。Fragment 也能进来，因为是单例Fragment也能进来。 LayoutInflater.from(this)
            skinChangeListener.changeSkin(mSkinResources);
        }
    }

    /**
     * 初始化皮肤的Resource
     *
     * @param path 原apk 或 皮肤插件的路径path
     */
    private void initSkinResource(String path) {
        mSkinResources = new SkinResource(mContext, path);
    }

    /**
     * 保存当前皮肤的信息
     *
     * @param path 当前皮肤的路径
     */
    private void saveSkinInfo(String path) {
        SkinPreUtils.getInstance(mContext).saveSkinPath(path);
    }

    /**
     * 恢复默认皮肤
     */
    public int restoreDefault() {
        String currentSkinPath = SkinPreUtils.getInstance(mContext).getSkinPath();
        if (TextUtils.isEmpty(currentSkinPath)) { // 判断当前有没有皮肤。
            return SkinConfig.SKIN_CHANGE_NOTHING; // 1.没有皮肤，不需要换肤。避免消耗内存
        }
        // 2.恢复：当前运行主app自己的 apk路径(非 换肤插件的路径)。
        String path = mContext.getPackageResourcePath(); // 拿到运行的 apk自己的路径: data/data/...
        initSkinResource(path); // 初始化皮肤资源
        changeSkin(); // 换肤操作，换成默认的皮肤
        clearSkinInfo(); // 恢复默认，清空设置的皮肤路径的信息

        return SkinConfig.SKIN_CHANGE_SUCCESS; // 3.恢复默认皮肤，换肤成功
    }

    /**
     * 清空皮肤信息
     */
    private void clearSkinInfo() {
        SkinPreUtils.getInstance(mContext).clearSkinInfo();
    }

    // 通过Activity， 获取SkinView列表
    public List<SkinView> getSkinViews(Activity activity) {
        return mSkinViews.get(activity);
    }

    public boolean isChangeSkin() {
        return SkinPreUtils.getInstance(mContext).needChangeSkin();
    }

    public void changeSkin(SkinView skinView) {
        skinView.skin();
    }

    /**
     * 注册监听回调
     */
    public void register(List<SkinView> skinViews, ISkinChangeListener skinChangeListener) {
        // 加入到map集合中。
        mSkinViews.put(skinChangeListener, skinViews);
    }

    /**
     * 从集合中移除，防止引起内存泄露
     */
    public void unregister(ISkinChangeListener skinChangeListener) {
        // 从集合中移除
        mSkinViews.remove(skinChangeListener);
    }

    // 获取当前的皮肤资源
    public SkinResource getSkinResource() {
        return mSkinResources;
    }

    /**
     * 检测要不要换肤，要换肤就进行皮肤更换。
     *
     * @param skinView
     */
    public void checkChangeSkin(SkinView skinView) {
        // 如果单前有皮肤，也就是保存了皮肤的路径，就换肤
        String currentSkinPath = SkinPreUtils.getInstance(mContext).getSkinPath();
        if (!TextUtils.isEmpty(currentSkinPath)) {
            // 切换皮肤
            skinView.skin();
        }
    }
}
